a tool for shared writing and social publishing
at update/reader 91 lines 3.2 kB view raw
1import { z } from "zod"; 2import type { Fact } from "src/replicache"; 3import type { Attribute } from "src/replicache/attributes"; 4import { makeRoute } from "../lib"; 5import type { Env } from "./route"; 6import { scanIndexLocal } from "src/replicache/utils"; 7import * as base64 from "base64-js"; 8import { YJSFragmentToString } from "src/utils/yjsFragmentToString"; 9import { applyUpdate, Doc } from "yjs"; 10 11export const getFactsFromHomeLeaflets = makeRoute({ 12 route: "getFactsFromHomeLeaflets", 13 input: z.object({ 14 tokens: z.array(z.string()), 15 }), 16 handler: async ({ tokens }, { supabase }: Pick<Env, "supabase">) => { 17 let all_facts = await supabase.rpc("get_facts_for_roots", { 18 max_depth: 3, 19 roots: tokens, 20 }); 21 22 if (all_facts.data) { 23 let titles = {} as { [key: string]: string }; 24 25 let facts = all_facts.data.reduce( 26 (acc, fact) => { 27 if (!acc[fact.root_id]) acc[fact.root_id] = []; 28 acc[fact.root_id].push(fact as unknown as Fact<Attribute>); 29 return acc; 30 }, 31 {} as { [key: string]: Fact<Attribute>[] }, 32 ); 33 for (let token of tokens) { 34 let scan = scanIndexLocal(facts[token]); 35 let [root] = scan.eav(token, "root/page"); 36 let rootEntity = root?.data.value || token; 37 38 // Check page type to determine which blocks to look up 39 let [pageType] = scan.eav(rootEntity, "page/type"); 40 let isCanvas = pageType?.data.value === "canvas"; 41 42 // Get blocks and sort by position 43 let rawBlocks = isCanvas 44 ? scan.eav(rootEntity, "canvas/block").sort((a, b) => { 45 if (a.data.position.y === b.data.position.y) 46 return a.data.position.x - b.data.position.x; 47 return a.data.position.y - b.data.position.y; 48 }) 49 : scan.eav(rootEntity, "card/block").sort((a, b) => { 50 if (a.data.position === b.data.position) 51 return a.id > b.id ? 1 : -1; 52 return a.data.position > b.data.position ? 1 : -1; 53 }); 54 55 // Map to get type and filter for text/heading 56 let blocks = rawBlocks 57 .map((b) => { 58 let type = scan.eav(b.data.value, "block/type")[0]; 59 if ( 60 !type || 61 (type.data.value !== "text" && type.data.value !== "heading") 62 ) 63 return null; 64 return b.data; 65 }) 66 .filter((b): b is NonNullable<typeof b> => b !== null); 67 68 let title = blocks[0]; 69 70 if (!title) titles[token] = "Untitled"; 71 else { 72 let [content] = scan.eav(title.value, "block/text"); 73 if (!content) titles[token] = "Untitled"; 74 else { 75 let doc = new Doc(); 76 const update = base64.toByteArray(content.data.value); 77 applyUpdate(doc, update); 78 let nodes = doc.getXmlElement("prosemirror").toArray(); 79 let stringValue = YJSFragmentToString(nodes[0]); 80 titles[token] = stringValue; 81 } 82 } 83 } 84 return { 85 result: { facts, titles }, 86 }; 87 } 88 89 return { result: {} }; 90 }, 91});